/**
* @author Ucar Sahin
*
* 07.06.2011
* DayTable.java
* 
*/

package at.fhv.easyDietWeb.shared.util;

import java.util.LinkedList;
import java.util.List;

import at.fhv.easyDietWeb.client.protocolService.IProtocolService;
import at.fhv.easyDietWeb.client.protocolService.IProtocolServiceAsync;
import at.fhv.easyDietWeb.client.protocolService.ProtocolPanel;
import at.fhv.easyDietWeb.shared.util.wrappers.DayWrapper;
import at.fhv.easyDietWeb.shared.util.wrappers.FoodListWrapper;
import at.fhv.easyDietWeb.shared.util.wrappers.FoodWrapper;
import at.fhv.easyDietWeb.shared.util.wrappers.MealLineWrapper;
import at.fhv.easyDietWeb.shared.util.wrappers.UnitsWrapper;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.MultiWordSuggestOracle;
import com.google.gwt.user.client.ui.SuggestBox;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;

/**
 * a table which organizes and shows the form for the nutritional journal
 * @author Spiegel Philipp
 *
 */
public class DayTable extends FlexTable
{
	private ListBox _mealTypeBox;
	private List<String> _mealTypes;
	private Button _addMealButton;
	private String _day;
	
	private MultiWordSuggestOracle _oracle;
	private List<FoodWrapper> _foodList;
	private List<String> _units;
	private IProtocolServiceAsync _ps;
	
	private ProtocolData _protocol;
	private Button _saveDayButton;
	
	/**
	 * constructor
	 * @param foodList
	 * @param mealTypes
	 */
	public DayTable(String day, List<String> mealTypes, ProtocolData protocol)
	{
		super();
		
		_day = day;
		_protocol = protocol;
		_foodList = new LinkedList<FoodWrapper>();
		_units = new LinkedList<String>();
		_mealTypes = mealTypes;
		_ps = GWT.create(IProtocolService.class);
		init();
	}
	
	/**
	 * initializes the day table
	 */
	public void init()
	{
		loadUnits();
		_mealTypeBox = new ListBox();		
		_addMealButton = new Button("Mahlzeit hinzufuegen");
		_addMealButton.addClickHandler(new ClickHandler()
										{
											@Override
											public void onClick(ClickEvent evt)
											{
												addMealInnerTable();
											}
										});
		
		for (String s : _mealTypes)
		{
			_mealTypeBox.addItem(s);
		}
		
		//init saveDayButton
        _saveDayButton = new Button("Tag speichern");
        _saveDayButton.addClickHandler(new ClickHandler()
							        {										
										@Override
										public void onClick(ClickEvent evt)
										{
											List<MealLineWrapper> mealLines = new LinkedList<MealLineWrapper>();
											List<FlexTable> mealTables = new LinkedList<FlexTable>();
											
											fillMealLines(mealLines);
											fillMealTables(mealTables);											
											
											DayWrapper day = new DayWrapper(_day, mealLines);
											
											if (!_protocol.containsDay(day))
											{
        										_protocol.addDay(day);
											}
											else
											{
												_protocol.overrideDay(day);
											}
											
											ProtocolPanel pp = (ProtocolPanel) getParent().getParent();
											pp.daySaved(day.getDay());
										}
									});
		
		setWidth("540px");
		setCellSpacing(5);
		
		Label dayLabel = new Label(_day);
		dayLabel.setStyleName("boldHeader");
		
		setWidget(0, 0, dayLabel);
		setWidget(0, 3, _saveDayButton);
		
		setWidget(1, 0, _mealTypeBox);
		setWidget(1, 1, _addMealButton);
		
		CellFormatter cellFormatter = getCellFormatter();
		cellFormatter.setHorizontalAlignment(0, 0, HasHorizontalAlignment.ALIGN_CENTER);
		cellFormatter.setHorizontalAlignment(1, 0, HasHorizontalAlignment.ALIGN_RIGHT);
		cellFormatter.setHorizontalAlignment(1, 1, HasHorizontalAlignment.ALIGN_LEFT);
		
		_oracle = new MultiWordSuggestOracle();
	}

	private void fillMealTables(List<FlexTable> mealTables)
	{
		if (getRowCount() > 2)
		{
			for (int i = 2; i < getRowCount(); i++)
			{
				FlexTable mealTable = (FlexTable) getWidget(i, 0);
				mealTables.add(mealTable);
			}			
		}
	}

	private void fillMealLines(List<MealLineWrapper> mealLines)
	{
		if (getRowCount() > 2)
		{
			for (int i = 2; i < getRowCount(); i++)
			{
				FlexTable mealTable = (FlexTable) getWidget(i, 0);
				
				for (int j = 2; j < mealTable.getRowCount(); j++)
				{
					String meal = mealTable.getText(0, 0);
					
					SuggestBox foodBox = (SuggestBox) mealTable.getWidget(j, 0);
					TextBox mealBox = (TextBox) mealTable.getWidget(j, 1);
					ListBox unitBox = (ListBox) mealTable.getWidget(j, 2);
					
					String foodName = foodBox.getText();
					FoodWrapper food = null;
					
					for (FoodWrapper fW : _foodList)
					{
						if (fW.getName().equals(foodName))
						{
							food = fW;
						}
					}
					
					String amount = mealBox.getText();
					String unit = unitBox.getItemText(unitBox.getSelectedIndex());
					
					mealLines.add(new MealLineWrapper(meal, food, amount, unit));
				}
			}			
		}
	}

	/**
	 * adds a table as a form for the nutritional journal
	 */
	protected void addMealInnerTable()
	{
		final int actualRow = getRowCount();
		
		//format the day table
		FlexCellFormatter cellFormatter = getFlexCellFormatter();
		cellFormatter.setColSpan(actualRow, 0, 4);
		cellFormatter.setHorizontalAlignment(actualRow, 0, HasHorizontalAlignment.ALIGN_CENTER);
		
		final FlexTable mealTable = new FlexTable();
		mealTable.setStyleName("mealTable");
		mealTable.setCellSpacing(5);
		
		FlexCellFormatter mealTableCellFormatter = mealTable.getFlexCellFormatter();
		mealTableCellFormatter.setColSpan(0, 0, 4);
		mealTableCellFormatter.setHorizontalAlignment(0, 0, HasHorizontalAlignment.ALIGN_LEFT);
				
		int index = _mealTypeBox.getSelectedIndex();
		String meal = _mealTypeBox.getItemText(index);
		
		//create a button to add a food
		Button addButton = new Button("+");
		addButton.setStyleName("addFoodButton");
		addButton.setTitle("Nahrungsmittel hinzufuegen");
		
		addButton.addClickHandler(new ClickHandler()
		{										
			@Override
			public void onClick(ClickEvent evt)
			{
				createMealLine(mealTable.getRowCount(), mealTable);
			}
		});
		
		//set the widgets of the new meal table
		Label mealLabel = new Label(meal);
		mealLabel.setStyleName("boldHeader");
		
		Label foodLabel = new Label("Nahrungsmittel");
		foodLabel.setStyleName("boldHeader");
		
		Label amountLabel = new Label("Menge");
		amountLabel.setStyleName("boldHeader");
		
		Label unitLabel = new Label("Einheit");
		unitLabel.setStyleName("boldHeader");
		
		mealTable.setWidget(0, 0, mealLabel);
		mealTable.setWidget(0, 4, addButton);
				
		mealTable.setWidget(1, 0, foodLabel);
		mealTable.setWidget(1, 1, amountLabel);
		mealTable.setWidget(1, 2, unitLabel);
		
		//add a first empty entry
		createMealLine(mealTable.getRowCount(), mealTable);		
		
		//add mealtable to the daytable
		setWidget(actualRow, 0, mealTable);
	}
	
	/**
	 * adds a new meal line to the meal table
	 * @param actualRow the new row to be added
	 * @param mealTable table, which should be extended by a further meal line
	 */
	private void createMealLine(final int actualRow, final FlexTable mealTable)
	{
		final SuggestBox foodField = new SuggestBox(_oracle);
		final ListBox unitBox = new ListBox();
		Button removeMealLineButton = new Button("-");
		removeMealLineButton.setStyleName("removeFoodButton");
		TextBox amountBox = new TextBox();
		
		//set a combo box with the possible units
		unitBox.addItem("Bitte auswaehlen");
		for (String s : _units)
		{
			unitBox.addItem(s);
		}
		
		//add a handler to the food field, which recognize the key "enter"
		foodField.setWidth("230px");
		foodField.addKeyPressHandler(new KeyPressHandler() 
											{			
												@Override
												public void onKeyPress(KeyPressEvent evt)
												{
													if (evt.getUnicodeCharCode() == 13)
													{
														String searchText = foodField.getText();
														
														if (!searchText.equals(""))
														{
															//provide suggestions
															getFoodList(searchText, foodField);
														}
													}
												}
											});
		
		//add a handler for the button, which removes its meal line
		removeMealLineButton.addClickHandler(new ClickHandler()
											{												
												@Override
												public void onClick(ClickEvent evt)
												{
													Button b = (Button) evt.getSource();
													mealTable.removeRow(getButtonRow(b, mealTable));
												}
											});
		
		//amountBox init
		amountBox.setWidth("40px");
		
		//set widgets for the new row
		mealTable.setWidget(actualRow, 0, foodField);
		mealTable.setWidget(actualRow, 1, amountBox);
		mealTable.setWidget(actualRow, 2, unitBox);
		mealTable.setWidget(actualRow, 3, removeMealLineButton);
	}

	/**
	 * searches for the row, which contains the remove button
	 * @param b remove button
	 * @param mealTable meal table to search in
	 * @return
	 */
	private int getButtonRow(Button b, FlexTable mealTable)
	{
		int row = 0;
		
		for (int i = mealTable.getRowCount()-1; i > 1; i--)
		{
			if (mealTable.getWidget(i, 3) == b)
			{
				row = i;
			}
		}
		
		return row;
	}

	/**
	 * loads and shows suggestions for the food from the server
	 * @param name
	 * @param foodField
	 */
	private void getFoodList(String name, final SuggestBox foodField)
	{
		_ps.getFoodList(name, new AsyncCallback<FoodListWrapper>()
						{
							@Override
							public void onSuccess(FoodListWrapper result)
							{
								if (result != null)
								{
									//refresh the oracle from the suggest box
									_foodList = result.getFoodList();
									_oracle.clear();
									
									for (FoodWrapper fw : _foodList)
									{
										_oracle.add(fw.getName());
									}
									
									//show the suggestions
									foodField.showSuggestionList();
								}
								else
								{
									final DialogBox db = new DialogBox();
									db.setTitle("Suchfehler");
									
									VerticalPanel dialogLayout = new VerticalPanel();
									dialogLayout.setSpacing(5);
									
									FlexTable ft = new FlexTable();
									ft.setHTML(0, 0, "Kein Nahrungsmittel anhand vom Suchkriterium gefunden!");
									
									Button closeButton = new Button("schliessen");
									closeButton.addClickHandler(new ClickHandler() 
																{								
																	@Override
																	public void onClick(ClickEvent arg0)
																	{
																		db.hide();
																	}
																});
									
									dialogLayout.add(ft);
									dialogLayout.add(closeButton);
									db.add(dialogLayout);
									db.center();
									db.show();
								}
							}
							
							@Override
							public void onFailure(Throwable caught)
							{
								DialogBox db = new DialogBox();
								db.setTitle("Server Error");
								VerticalPanel dialogLayout = new VerticalPanel();
								dialogLayout.setSpacing(5);
								db.add(dialogLayout);
								
								FlexTable ft = new FlexTable();
								ft.setHTML(0, 0, "verbindungsaufbau zum server gescheitert! bitte ueberpruefen sie ihre"
											   + " Netzwerkverbindung und ueberpruefen sie es erneut!");
								
								db.add(dialogLayout);
							}
						});
	}
	
	/**
	 * loads the possible units for the food
	 */
	private void loadUnits()
	{
		_ps.loadUnits(new AsyncCallback<UnitsWrapper>() 
						{						
							@Override
							public void onSuccess(UnitsWrapper result)
							{
								_units = result.getUnits();
							}
							
							@Override
							public void onFailure(Throwable caught)
							{
								DialogBox db = new DialogBox();
								db.setTitle("Server Error");
								VerticalPanel dialogLayout = new VerticalPanel();
								dialogLayout.setSpacing(5);
								db.add(dialogLayout);
								
								FlexTable ft = new FlexTable();
								ft.setHTML(0, 0, "verbindungsaufbau zum server gescheitert! bitte ueberpruefen sie ihre"
											   + " Netzwerkverbindung und ueberpruefen sie es erneut!");
								
								db.add(dialogLayout);
							}
						});
	}
}
